﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SOWY.common;

namespace SOWY
{
    class DateProcessor
    {
        private string dateToProcess;
        private string dateTypeKeywords;
        private string startOrEnd;
        private int dayToAdd;
        private DateTime comparator;

        #region constructor
        public DateProcessor()
        {
            dateToProcess = "";
            dateTypeKeywords = "";
            startOrEnd = "";
            dayToAdd = 0;
        }
        public DateProcessor(string input, string dateType)
        {
            dateToProcess = input;
            dateTypeKeywords = dateType;
            startOrEnd = "";
        }
        public DateProcessor(string input, string dateType, string startEnd)
        {
            dateToProcess = input;
            dateTypeKeywords = dateType;
            startOrEnd = startEnd;
        }
        public DateProcessor(string input, string dateType, string startEnd, DateTime compare)
        {
            dateToProcess = input;
            dateTypeKeywords = dateType;
            startOrEnd = startEnd;
            comparator = compare;
        }
        #endregion

        public DateTime processDate()
        {
            DateTime formattedDate;
            DateFormatter df = new DateFormatter(dateToProcess);
            dateToProcess = df.formatDate();

            if (DateTime.TryParse(dateToProcess, out formattedDate)) //convert succeed
                return formattedDate;
            else
            {
                dateToProcess = checkDayAfterTomorrow(dateToProcess);
                dateToProcess.Trim();
                string[] workTokens = dateToProcess.Split(GeneralConstant.DELIMITER_SPACE);

                processStringWithNumberAffix(workTokens);

                if (DateTime.TryParse(dateToProcess, out formattedDate)) //convert succeed
                {
                    if (formattedDate < DateTime.Now)
                        return formattedDate.AddYears(1);
                    else
                        return formattedDate;
                }

                else
                {
                    formattedDate = processDateManual(workTokens);

                    for (int i = 0; i < workTokens.Length; i++)
                    {
                        checkTomorrow(workTokens[i]);
                        checkYesterday(workTokens[i]);
                    }
                    formattedDate = formattedDate.AddDays(dayToAdd);
                }
                return formattedDate;
            }
        }
        private void processStringWithNumberAffix(string[] workTokens)
        {
            if (parseIntWithAffix(workTokens[0], 31) != 0)
            {
                workTokens[0] = parseIntWithAffix(workTokens[0], 31).ToString();
                dateToProcess = "";
                for (int i = 0; i < workTokens.Length; i++)
                    dateToProcess += workTokens[i] + " ";
                dateToProcess.Trim();
            }
        }
        private DateTime processDateManual(string[] workTokens)
        {
            DateTime formattedDate = DateTime.Now;
            switch (workTokens.Length)
            {
                case 1: formattedDate = processOneWordString(workTokens);
                    break;

                case 2: formattedDate = processTwoWordString(workTokens);
                    break;

                case 3: formattedDate = processThreeWordsString(workTokens);
                    break;

                case 4: formattedDate = processFourWordsString(workTokens);
                    break;

                default: formattedDate = DateTime.MinValue;
                    break;
            }
            return formattedDate;
        }

        #region one word processing
        private DateTime processOneWordString(string[] workTokens)
        {
            //check if the string is empty, if it is, user did not entered any date and should be a floating task regardless of keyword
            if (workTokens[0].Length == 0)
            {
                this.dateTypeKeywords = "";
                return DateTime.Now;
                //in the event of a accidental floating task, the dates are not necessary anymore, so we just return a date that will not cause any error
            }
            else
            {
                DateTime dates = DateTime.MinValue;
                int possibleDay = checkDays(workTokens[0]);
                int possibleMonth = checkMonths(workTokens[0]);
                int possibleYear = checkYear(workTokens[0]);

                if (checkTomorrow(workTokens[0]) || checkYesterday(workTokens[0]))
                {
                    dayToAdd = 0;
                    dates = DateTime.Now;
                }
                if (possibleDay != 0)
                    dates = processOneWordDay(possibleDay);
                if (possibleMonth != 0)
                    dates = processOneWordMonth(possibleMonth);
                if (possibleYear != 0)
                    dates = processOneWordYear(possibleYear);
                
                return dates;
            }
        }

        private DateTime processOneWordYear(int input)
        {
            DateTime date = goToEndofInputYear(input);

            if (dateTypeKeywords.ToLower().CompareTo(GeneralConstant.KEY_BETWEEN) == 0)
            {
                if (startOrEnd.CompareTo("start") == 0)
                    date = goToStartofInputYear(input);
                else
                    date = goToEndofInputYear(input);
            }
            if (date < DateTime.Now)
                date = DateTime.Now;

            return date;
        }
        private DateTime processOneWordMonth(int input)
        {
            DateTime date = goToEndofInputMonth(input);

            if (dateTypeKeywords.ToLower().CompareTo(GeneralConstant.KEY_BETWEEN) == 0)
            {
                if (startOrEnd.CompareTo("start") == 0)
                    date = goToStartOfInputMonth(input);
                else
                    date = goToEndofInputMonth(input);
            }
            if (date < DateTime.Now)
                date = DateTime.Now;

            return date;
        }
        private DateTime processOneWordDay(int input)
        {
            DateTime now = DateTime.Today;
            int currentDay = checkDays(now.DayOfWeek.ToString());
            while (currentDay != input)
            {
                now = now.AddDays(1.0);
                currentDay = checkDays(now.DayOfWeek.ToString());
            }
            if (dateTypeKeywords.ToLower().CompareTo(GeneralConstant.KEY_BETWEEN) == 0 && comparator.Year != 1)
            {
                if (now < comparator)
                    now = now.AddDays(7);
            }
            return now;
        }
        #endregion

        #region 2 word processing
        private DateTime processTwoWordString(string[] workTokens)
        {
            string thisOrNext = "this";
            if (workTokens[0].ToLower().Trim().CompareTo("next") == 0)
            {
                thisOrNext = "next";
            }
            if (workTokens[0].ToLower().Trim().CompareTo("this") == 0)
            {
                thisOrNext = "this";
            }
            if (workTokens[0].ToLower().Trim().CompareTo("last") == 0)
            {
                thisOrNext = "last";
            }
            return processSecondToken(workTokens[1], thisOrNext);
        }
        private DateTime processSecondToken(string word, string thisOrNext)
        {
            switch (word)
            {
                case "week": return processWeek(thisOrNext, DateTime.Now);

                case "day": return processDay(thisOrNext, DateTime.Now);

                case "month": return processMonth(thisOrNext, DateTime.Now);

                case "year": return processYear(thisOrNext, DateTime.Now);

                case "weekend": return processWeekend(thisOrNext, DateTime.Now);

                default: return processSpecial(thisOrNext, word, DateTime.Now);
            }
        }
        
        private DateTime processWeek(string thisOrNext, DateTime toReturn)
        {
            if (thisOrNext.CompareTo("next") == 0)
                toReturn = toReturn.AddDays(7);
            if (thisOrNext.CompareTo("last") == 0)
                toReturn = toReturn.AddDays(-7);

            if ((dateTypeKeywords.CompareTo(GeneralConstant.KEY_BETWEEN) == 0) && (startOrEnd.CompareTo("start") == 0))
            {
                if(goToStartofWeek(toReturn) < DateTime.Now)
                    return DateTime.Now;
                else
                    return goToStartofWeek(toReturn);
            }
            else
                return goToEndofWeek(toReturn);
        }
        private DateTime processDay(string thisOrNext, DateTime toReturn)
        {
            if (thisOrNext.CompareTo("next") == 0)
                toReturn = toReturn.AddDays(1);
            if (thisOrNext.CompareTo("last") == 0)
                toReturn = toReturn.AddDays(-1);

            return toReturn;
        }
        private DateTime processMonth(string thisOrNext, DateTime toReturn)
        {
            if (thisOrNext.CompareTo("next") == 0)
                toReturn = toReturn.AddMonths(1);
            if (thisOrNext.CompareTo("last") == 0)
                toReturn = toReturn.AddMonths(-1);

            if ((dateTypeKeywords.CompareTo(GeneralConstant.KEY_BETWEEN) == 0) && (startOrEnd.CompareTo("start") == 0))
            {
                toReturn =  goToStartOfInputMonth(toReturn.Month);
                return toReturn.AddYears(-1);
            }

            else
            {
                toReturn = goToEndofInputMonth(toReturn.Month);
                return toReturn.AddYears(-1);
            }
        }
        private DateTime processYear(string thisOrNext, DateTime toReturn)
        {
            if (thisOrNext.CompareTo("next") == 0)
                toReturn = toReturn.AddYears(1);
            if (thisOrNext.CompareTo("last") == 0)
                toReturn = toReturn.AddYears(-1);

            if ((dateTypeKeywords.CompareTo(GeneralConstant.KEY_BETWEEN) == 0) && (startOrEnd.CompareTo("start") == 0))
                return goToStartofInputYear(toReturn.Year);

            else
                return goToEndofInputYear(toReturn.Year);
        }
        private DateTime processWeekend(string thisOrNext, DateTime toReturn)
        {
            if (thisOrNext.CompareTo("next") == 0)
                toReturn = toReturn.AddDays(7);
            if (thisOrNext.CompareTo("last") == 0)
                toReturn = toReturn.AddDays(-7);

            if ((dateTypeKeywords.CompareTo(GeneralConstant.KEY_BETWEEN) == 0) && (startOrEnd.CompareTo("start") == 0))
                return goToStartofWeek(toReturn).AddDays(5);

            else
                return goToEndofWeek(toReturn);
        }
        private DateTime processSpecial(string thisOrNext, string word, DateTime toReturn)
        {
            int toWhichDay = checkDays(word);
            int toWhichMonth = checkMonths(word);

            if (toWhichDay != 0)   //it is a day
                toReturn = processSpecialDay(toWhichDay, thisOrNext, toReturn);
            if (toWhichMonth != 0)
                toReturn = processSpecialMonth(toWhichMonth, thisOrNext, toReturn);

            return toReturn;
        }

        private DateTime processSpecialDay(int toWhichDay, string thisOrNext, DateTime toReturn)
        {
            if (thisOrNext.CompareTo("next") == 0)
                toReturn = toReturn.AddDays(7);
            if (thisOrNext.CompareTo("last") == 0)
                toReturn = toReturn.AddDays(-7);

            int currentDay = checkDays(toReturn.DayOfWeek.ToString());
            int diffBetweenDays = toWhichDay - currentDay;
            toReturn = toReturn.AddDays(diffBetweenDays);

            return toReturn;
        }
        private DateTime processSpecialMonth(int toWhichMonth, string thisOrNext, DateTime toReturn)
        {
            toReturn = goToEndofInputMonth(toReturn.Month);

            if (thisOrNext.CompareTo("next") == 0)
                toReturn = toReturn.AddYears(1);
            if (thisOrNext.CompareTo("last") == 0)
                toReturn = toReturn.AddYears(-1);

            int currentMonth = toReturn.Month;
            int diffBetweenMonth = toWhichMonth - currentMonth;
            toReturn = toReturn.AddMonths(diffBetweenMonth);

            if (dateTypeKeywords.ToLower().CompareTo(GeneralConstant.KEY_BETWEEN) == 0)
                if (startOrEnd.CompareTo("start") == 0)
                    toReturn= goToStartOfInputMonth(toReturn.Month);

            return toReturn;
        }
        #endregion

        #region 3 word processing
        private DateTime processThreeWordsString(string[] workTokens)
        {
            DateTime toReturn = DateTime.MinValue;

            toReturn = processThreeWordWeek(workTokens, toReturn);
            toReturn = processThreeWordYear(workTokens, toReturn);
            toReturn = processThreeWordMonth(workTokens, toReturn);
            toReturn = processThreeWordSpecialMonth(workTokens, toReturn);
            toReturn = processThreeWordNumWeekInMonth(workTokens, toReturn);
            toReturn = processThreeWordNumWeekInYear(workTokens, toReturn);

            if (workTokens[0].ToLower().Trim().CompareTo(workTokens[1].ToLower().Trim()) == 0)
                toReturn = processDoubleNextAndLast(workTokens, DateTime.Now);
   
            return toReturn;
        }

        private DateTime processThreeWordWeek(string[] workTokens, DateTime toReturn)
        {
            string NextLastThis0 = workTokens[0].ToLower().Trim();
            bool isNextLastThis0 = (NextLastThis0.CompareTo("this") == 0 || NextLastThis0.CompareTo("next") == 0 || NextLastThis0.CompareTo("last") == 0);
            string NextLastThis1 = workTokens[1].ToLower().Trim();
            bool isNextLastThis1 = (NextLastThis1.CompareTo("this") == 0 || NextLastThis1.CompareTo("next") == 0 || NextLastThis1.CompareTo("last") == 0);

            //this week tues, next week tues, last week wed
            if (checkDays(workTokens[2]) != 0 && isNextLastThis0 && workTokens[1].ToLower().Trim().CompareTo("week") == 0)
                toReturn = processSpecialDay(checkDays(workTokens[2]), workTokens[0], DateTime.Now);

            //mon this week, tue next week, thur last week
            if (checkDays(workTokens[0]) != 0 && isNextLastThis1 && workTokens[2].ToLower().Trim().CompareTo("week") == 0)
                toReturn = processSpecialDay(checkDays(workTokens[0]), workTokens[1], DateTime.Now);

            return toReturn;
        }
        private DateTime processThreeWordYear(string[] workTokens, DateTime toReturn)
        {
            string NextLastThis0 = workTokens[0].ToLower().Trim();
            bool isNextLastThis0 = (NextLastThis0.CompareTo("this") == 0 || NextLastThis0.CompareTo("next") == 0 || NextLastThis0.CompareTo("last") == 0);
            string NextLastThis1 = workTokens[1].ToLower().Trim();
            bool isNextLastThis1 = (NextLastThis1.CompareTo("this") == 0 || NextLastThis1.CompareTo("next") == 0 || NextLastThis1.CompareTo("last") == 0);

            //this year jan, next year mar, last year dec
            if (checkMonths(workTokens[2]) != 0 && isNextLastThis0 && workTokens[1].ToLower().Trim().CompareTo("year") == 0)
                toReturn = processSpecialMonth(checkMonths(workTokens[2]), workTokens[0], DateTime.Now);

            //dec this year, may next year, apr last year
            if (checkMonths(workTokens[0]) != 0 && isNextLastThis1 && workTokens[2].ToLower().Trim().CompareTo("year") == 0)
                toReturn = processSpecialMonth(checkMonths(workTokens[0]), workTokens[1], DateTime.Now);

            return toReturn;
        }
        private DateTime processThreeWordMonth(string[] workTokens, DateTime toReturn)
        {
            string NextLastThis0 = workTokens[0].ToLower().Trim();
            bool isNextLastThis0 = (NextLastThis0.CompareTo("this") == 0 || NextLastThis0.CompareTo("next") == 0 || NextLastThis0.CompareTo("last") == 0);
            int parsedDate0 = parseIntWithAffix(workTokens[2], 31);

            string NextLastThis1 = workTokens[1].ToLower().Trim();
            bool isNextLastThis1 = (NextLastThis1.CompareTo("this") == 0 || NextLastThis1.CompareTo("next") == 0 || NextLastThis1.CompareTo("last") == 0);
            int parsedDate1 = parseIntWithAffix(workTokens[0], 31);

            //this month 21st, next month 3rd, last month 16th
            if (isNextLastThis0 && workTokens[1].ToLower().Trim().CompareTo("month") == 0 && parsedDate0 !=0)
            {
                toReturn = processMonth(workTokens[0], DateTime.Now);
                try
                {
                    toReturn = new DateTime(toReturn.Year, toReturn.Month, parsedDate0);
                }
                catch (Exception)
                {
                    toReturn = DateTime.MinValue;
                }
            }

            //30th this month, 1st next month, 4th last month
            if (isNextLastThis1 && workTokens[2].ToLower().Trim().CompareTo("month") == 0 && parsedDate1 != 0)
            {
                toReturn = processMonth(workTokens[1], DateTime.Now);
                try
                {
                    toReturn = new DateTime(toReturn.Year, toReturn.Month, parsedDate1);
                }
                catch (Exception)
                {
                    toReturn = DateTime.MinValue;
                }
            }

            return toReturn;
        }
        private DateTime processThreeWordSpecialMonth(string[] workTokens, DateTime toReturn)
        {
            string NextLastThis0 = workTokens[0].ToLower().Trim();
            bool isNextLastThis0 = (NextLastThis0.CompareTo("this") == 0 || NextLastThis0.CompareTo("next") == 0 || NextLastThis0.CompareTo("last") == 0);
            int parsedDate0 = parseIntWithAffix(workTokens[2], 31);
            int month0 = checkMonths(workTokens[1]);

            string NextLastThis1 = workTokens[1].ToLower().Trim();
            bool isNextLastThis1 = (NextLastThis1.CompareTo("this") == 0 || NextLastThis1.CompareTo("next") == 0 || NextLastThis1.CompareTo("last") == 0);
            int parsedDate1 = parseIntWithAffix(workTokens[0],31);
            int month1 = checkMonths(workTokens[2]);

            //this month 21st, next month 3rd, last month 16th
            if (isNextLastThis0 && month0 != 0 && parsedDate0 != 0)
            {
                toReturn = processSpecialMonth(month0, workTokens[0], DateTime.Now);
                try
                {
                    toReturn = new DateTime(toReturn.Year, toReturn.Month, parsedDate0);
                }
                catch (Exception)
                {
                    toReturn = DateTime.MinValue;
                }
            }

            //30th this month, 1st next month, 4th last month
            if (isNextLastThis1 && month1 != 0 && parsedDate1 != 0)
            {
                toReturn = processSpecialMonth(month1, workTokens[1], DateTime.Now);
                try
                {
                    toReturn = new DateTime(toReturn.Year, toReturn.Month, parsedDate1);
                }
                catch (Exception)
                {
                    toReturn = DateTime.MinValue;
                }
            }

            return toReturn;
        }
        private DateTime processThreeWordNumWeekInMonth(string[] workTokens, DateTime toReturn)
        {
            bool isWeek0 = (workTokens[2].CompareTo("week") == 0);
            int parsedWeekNum0 = parseIntWithAffix(workTokens[1], 5);
            int month0 = checkMonths(workTokens[0]);

            bool isWeek1 = (workTokens[1].CompareTo("week") == 0);
            int parsedWeekNum1 = parseIntWithAffix(workTokens[0], 5);
            int month1 = checkMonths(workTokens[2]);

            //jan last week, feb 3rd week, jun first week
            if (isWeek0 && month0 != 0 && parsedWeekNum0 != 0)
            {
                toReturn = processSpecialMonth(month0, workTokens[0], DateTime.Now);
                try
                {
                    toReturn = new DateTime(toReturn.Year, toReturn.Month, 1);
                    for (int i = 0; i < parsedWeekNum0; i++)
                    {
                        toReturn = goToEndofWeek(toReturn);
                        toReturn = toReturn.AddDays(1);
                    }
                    toReturn = toReturn.AddDays(-1);
                }
                catch (Exception)
                {
                    toReturn = DateTime.MinValue;
                }
            }

            //last week jan, 3rd week feb
            if (isWeek1 && month1 != 0 && parsedWeekNum1 != 0)
            {
                toReturn = processSpecialMonth(month1, workTokens[2], DateTime.Now);
                try
                {
                    toReturn = new DateTime(toReturn.Year, toReturn.Month, 1);
                    for (int i = 0; i < parsedWeekNum1; i++)
                    {
                        toReturn = goToEndofWeek(toReturn);
                        toReturn = toReturn.AddDays(1);
                    }
                    toReturn = toReturn.AddDays(-1);
                }
                catch (Exception)
                {
                    toReturn = DateTime.MinValue;
                }
            }

            return toReturn;
        }
        private DateTime processThreeWordNumWeekInYear(string[] workTokens, DateTime toReturn)
        {
            bool isWeek0 = (workTokens[2].CompareTo("week") == 0);
            int parsedWeekNum0 = parseIntWithAffix(workTokens[1], 52);
            int year0 = checkYear(workTokens[0]);

            bool isWeek1 = (workTokens[1].CompareTo("week") == 0);
            int parsedWeekNum1 = parseIntWithAffix(workTokens[0], 52);
            int year1 = checkYear(workTokens[2]);

            //2012 last week, 2014 33rd week, 2011 first week
            if (isWeek0 && year0 != 0 && parsedWeekNum0 != 0)
            {
                toReturn = DateTime.Now;
                try
                {
                    toReturn = new DateTime(year0, 1, 1);
                    for (int i = 0; i < parsedWeekNum0; i++)
                    {
                        toReturn = toReturn.AddDays(7);
                    }
                    toReturn = goToEndofWeek(toReturn);
                }
                catch (Exception)
                {
                    toReturn = DateTime.MinValue;
                }
            }

            //last week 2012, 3rd week 2015
            if (isWeek1 && year1 != 0 && parsedWeekNum1 != 0)
            {
                toReturn = DateTime.Now;
                try
                {
                    toReturn = new DateTime(year1, 1, 1);
                    for (int i = 0; i < parsedWeekNum1; i++)
                    {
                        toReturn = toReturn.AddDays(7);
                    }
                    toReturn = goToEndofWeek(toReturn);
                }
                catch (Exception)
                {
                    toReturn = DateTime.MinValue;
                }
            }

            return toReturn;
        }
        private DateTime processDoubleNextAndLast(string[] workTokens, DateTime toReturn)
        {
            for (int i = 0; i < 2; i++)
            {
                switch (workTokens[2].ToLower().Trim())
                {
                    case "day": toReturn = processDay(workTokens[i], toReturn);
                        break;

                    case "week": toReturn = processWeek(workTokens[i], toReturn);
                        break;

                    case "month": toReturn = processMonth(workTokens[i], toReturn);
                        break;

                    case "year": toReturn = processYear(workTokens[i], toReturn);
                        break;

                    case "weekend": toReturn = processWeekend(workTokens[i], toReturn);
                        break;

                    default: toReturn = processSpecial(workTokens[i], workTokens[2], toReturn);
                        break;
                }
            }
            return toReturn;
        }
        #endregion

        #region 4 word processing
        private DateTime processFourWordsString(string[] workTokens)
        {
            DateTime toReturn = DateTime.MinValue;

            if (workTokens[0].ToLower().Trim().CompareTo(workTokens[1].ToLower().Trim()) == 0 && workTokens[0].ToLower().Trim().CompareTo(workTokens[2].ToLower().Trim()) == 0)
                toReturn = processTripleNextAndLast(workTokens, DateTime.Now);

            return toReturn;
        }
        private DateTime processTripleNextAndLast(string[] workTokens, DateTime toReturn)
        {
            for (int i = 0; i < 3; i++)
            {
                switch (workTokens[3].ToLower().Trim())
                {
                    case "day": toReturn = processDay(workTokens[i], toReturn);
                        break;

                    case "week": toReturn = processWeek(workTokens[i], toReturn);
                        break;

                    case "month": toReturn = processMonth(workTokens[i], toReturn);
                        break;

                    case "year": toReturn = processYear(workTokens[i], toReturn);
                        break;

                    case "weekend": toReturn = processWeekend(workTokens[i], toReturn);
                        break;

                    default: toReturn = processSpecial(workTokens[i], workTokens[3], toReturn);
                        break;
                }
            }
            return toReturn;
        }
        #endregion

        #region start/End of Year/Month/week Function
        private DateTime goToStartOfInputMonth(int input)
        {
            DateTime now = DateTime.Today;
            int currentMonth = now.Month;
            while (currentMonth != input)
            {
                now = now.AddMonths(1);
                currentMonth = now.Month;
            }
            DateTime newDate = new DateTime(now.Year, now.Month, 1);
            return newDate;
        }
        private DateTime goToEndofInputMonth(int input)
        {
            DateTime now = DateTime.Today;
            int currentMonth = now.Month;
            while (currentMonth != input)
            {
                now = now.AddMonths(1);
                currentMonth = now.Month;
            }
            int numOfDays = DateTime.DaysInMonth(now.Year, now.Month);
            DateTime newDate = new DateTime(now.Year, now.Month, numOfDays);
            return newDate;
        }

        private DateTime goToStartofInputYear(int input)
        {
            DateTime Now = new DateTime(input, 1, 1);
            return Now;
        }
        private DateTime goToEndofInputYear(int input)
        {
            DateTime Now = new DateTime(input, 12, 31);
            return Now;
        }

        private DateTime goToEndofWeek(DateTime input)
        {
            if (input.DayOfWeek == DayOfWeek.Sunday)
                return input;
            else
            {
                DayOfWeek day = input.DayOfWeek;
                int days = day - DayOfWeek.Monday;
                DateTime start = input.AddDays(-days);
                DateTime end = start.AddDays(6);
                return end;
            }
        }
        private DateTime goToStartofWeek(DateTime input)
        {
            if (input.DayOfWeek == DayOfWeek.Sunday)
                return input.AddDays(-6);
            else
            {
                DayOfWeek day = input.DayOfWeek;
                int days = day - DayOfWeek.Monday;
                DateTime start = input.AddDays(-days);
                return start;
            }
        }
        #endregion

        #region Checking/parsing Functions
        private bool checkTomorrow(string input)
        {
            if (input.ToLower().CompareTo("tomorrow") == 0 || input.ToLower().CompareTo("tmr") == 0)
            {
                dayToAdd++;
                return true;
            }
            return false;
        }
        private string checkDayAfterTomorrow(string input)
        {
            input = input.Trim();
            if (input.ToLower().Contains("day after tmr")|| input.ToLower().Contains("day after tomrrow")|| input.ToLower().Contains("day aft tomrrow")|| input.ToLower().Contains("day aft tmr"))
            {
                input = input.Replace("day after tmr", "");
                input = input.Replace("day after tomrrow", "");
                input = input.Replace("day aft tomrrow", "");
                input = input.Replace("day aft tmr", "");
                dayToAdd += 2;
            }
            return input;
        }
        private bool checkYesterday(string input)
        {
            if (input.ToLower().CompareTo("yesterday") == 0 || input.ToLower().CompareTo("ytd") == 0)
            {
                dayToAdd--;
                return true;
            }
            return false;
        }

        private int checkDays(string input)
        {
            for (int i = 0; i < GeneralConstant.COMMON_NUMBER_OF_DAYS; i++)
            {
                if (GeneralConstant.DAY_LONG_ALL[i].ToLower().Contains(input.Trim().ToLower()))
                {
                    return ++i;
                }
            }
            return 0;
        }
        private int checkMonths(string input)
        {
            for (int i = 0; i < GeneralConstant.COMMON_NUMBER_OF_MONTHS; i++)
            {
                if (GeneralConstant.MONTH_LONG_ALL[i].ToLower().Contains(input.Trim().ToLower()))
                {
                    return ++i;
                }
            }
            return 0;
        }
        private int checkYear(string input)
        {
            int year;
            if (int.TryParse(input, out year))
            {
                   return year;
            }
            else
                return 0;
        }

        private int parseIntWithAffix(string input, int max)
        {
            int temp;
            if (Int32.TryParse(input, out temp))
            {
                if (temp > max)
                    return 0;
                else
                    return temp;
            }
            else if (input.Trim().CompareTo("first") == 0)
                return 1;
            else if (input.Trim().CompareTo("last") == 0)
                return max;
            else
            {
                for (int i = 0; i < max; i++)
                {
                    if (input.ToLower().Trim().CompareTo(GeneralConstant.COMMON_NUMBER_WITH_AFFIX[i]) == 0)
                        return ++i;
                }
                return 0;
            }
        }
        #endregion

    }
}
